<?php

declare (strict_types=1);

namespace magein\pay;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use magein\pay\data\NoticeData;
use magein\utils\Result;

class PayNotice
{

    /**
     * @param $pay_order
     * @param NoticeData|null $notifyData
     * @return array
     */
    public function getUrlParams($pay_order, NoticeData $notifyData = null): array
    {

        $query['pay_notify_type'] = $notifyData ? $notifyData->getNotifyType() : '';
        $query['pay_trade_no'] = $notifyData ? $notifyData->getTradeNo() : ($pay_order['trade_no'] ?? '');
        $query['pay_pay_no'] = $notifyData ? $notifyData->getPayNo() : ($pay_order['pay_no'] ?? '');
        $query['pay_result'] = $notifyData ? $notifyData->getResult() : ($pay_order['result'] ?? '');
        $query['pay_fail_reason'] = $notifyData ? $notifyData->getReason() : ($pay_order['reason'] ?? '');
        $query['pay_notify_date'] = $notifyData ? $notifyData->getNotifyDate() : ($pay_order['notify_date'] ?? '');
        $query['pay_trade_type'] = $notifyData ? $notifyData->getTradeType() : ($pay_order['trade_type'] ?? '');
        $query['pay_subject'] = $pay_order['subject'];
        $query['pay_order_no'] = $pay_order['order_no'] ?? '';
        $query['pay_platform_id'] = $pay_order['platform_id'] ?? '';
        $query['pay_user_id'] = $pay_order['user_id'] ?? '';
        $query['pay_total_amount'] = $pay_order['total_amount'] ?? '';
        $query['pay_coupon_amount'] = $pay_order['total_coupon_amount'] ?? '';

        try {
            $sign = PayFactory::singer()->create($query, $pay_order['channel_id']);
        } catch (PayException $payException) {
            $sign = '';
        }

        $query['sign'] = $sign;

        return $query;
    }

    protected function parseUrl($url): string
    {
        if (empty($url)) {
            return '';
        }

        $url = urldecode($url);
        $parse = parse_url($url);
        $scheme = $parse['scheme'] ?? '';
        $host = $parse['host'] ?? '';
        $path = $parse['path'] ?? '';

        if (empty($scheme) || empty($host)) {
            return '';
        }
        return sprintf('%s://%s%s', $scheme, $host, $path);
    }

    /**
     * @param array $pay_order
     * @param NoticeData|null $notifyData
     * @return string
     */
    public function getNotifyUrl(array $pay_order, NoticeData $notifyData = null): string
    {
        $url = $this->parseUrl($pay_order['notify_url'] ?? '');

        $notifyData->setNotifyType('notify');
        $params = self::getUrlParams($pay_order, $notifyData);

        $url .= '?' . http_build_query($params);

        return $url;
    }

    /**
     * @param array $pay_order
     * @param NoticeData|null $notifyData
     * @return string
     */
    public function getReturnUrl(array $pay_order, NoticeData $notifyData = null): string
    {
        $url = $this->parseUrl($pay_order['return_url'] ?? '');

        // 添加通知参数
        if (is_null($notifyData)) {
            $notifyData = new NoticeData();
        }
        $notifyData->setNotifyType('return');

        $params = self::getUrlParams($pay_order, $notifyData);
        $url .= '?' . http_build_query($params);

        return $url;
    }

    /**
     * @param NoticeData $notifyData
     * @param $pay_no
     * @return bool|Result
     */
    public function run(NoticeData $notifyData, $pay_no)
    {
        if (!$notifyData->isOk()) {
            return false;
        }

        if (is_string($pay_no)) {
            try {
                $pay_order = PayFactory::order()->getByPayNo($pay_no);
            } catch (PayException $exception) {
                return Result::error($exception->getMessage());
            }
        } else {
            $pay_order = $pay_no;
        }

        if (!is_array($pay_order)) {
            return false;
        }

        $url = self::getNotifyUrl($pay_order, $notifyData);

        try {
            $client = new Client();
            $response = $client->request('get', $url);
            $status_code = $response->getStatusCode();
            $content = $response->getBody()->getContents();
            PayFactory::log()->notice($status_code, $content, $pay_order);
        } catch (GuzzleException|PayException $e) {
            try {
                PayFactory::log()->debug('notice:' . $pay_no . ':' . $e->getMessage());
            } catch (PayException $exception) {

            }
        }

        return true;
    }
}